package com.egg.ylt.Utils;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.util.Log;

import com.alibaba.fastjson.JSON;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import okhttp3.WebSocket;

/**
 * Created By Dlx
 * on 2018/11/29 0029
 * 长连接工具类，可设置自动重连，心跳包，默认发送内容，通过callback返回数据
 */
public class SocketUtil<T> {
    //超时时间 默认10s
    private int reConnTime = 10;
    //目标ip
    private String ip;
    //端口
    private int port;
    //charsetname
    private String charsetName = "utf-8";
    //是否处于链接状态
    private boolean isConnected = false;
    //是否自动重连 默认是
    private  Boolean isAutoReconnect = true;
    //最大超时时间
    private long maxTimeout = 10000;
    //等待服务器响应
    private boolean waitResponce = false;
    //上次发送消息时间
    private  long lastTime = 0;
    //默认心跳包内容
    private String defaultMsg = "1";
    //是否自动发送心跳包
    private boolean keepAlive = true;
    private Socket socket = null;
    private InputStream inputStream;
    private BufferedReader in;
    private InputStreamReader inputStreamReader;
    private OutputStream outputStream;
    private  PrintWriter printWriter;
    private byte[] buffer = new byte[4096];
    private SocketCallBack<T> callBack;
    private static final String TAG = "SocketUtil";
    private ExecutorService executorService = new ThreadPoolExecutor(2, 5,
            60, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
    private Handler handler = new Handler(Looper.getMainLooper());


    public SocketUtil(@NonNull String ip, int port, @NonNull SocketCallBack<T> callBack) {
        this.ip = ip;
        this.port = port;
        this.callBack = callBack;
    }

    /**
     * 设置是否自动发送心跳包
     *
     * @param keepAlive
     */
    public void setKeepAlive(boolean keepAlive) {
        this.keepAlive = keepAlive;
    }

    /**
     * 设置心跳包默认发送内容
     *
     * @param msg
     */
    public void setDefaultMsg(String msg) {
        defaultMsg = msg;
    }

    /**
     * 设置重连时间 秒
     *
     * @param reConnTime
     */
    public void setReConnTime(int reConnTime) {
        this.reConnTime = reConnTime;
    }

    /**
     * 设置是否自动重连
     *
     * @param isAutoReconnect
     */
    public void setAutoReconnect(boolean isAutoReconnect) {
        this.isAutoReconnect = isAutoReconnect;
    }

    /**
     * 设置最大超时时间
     *
     * @param time 时间，单位毫秒
     */
    public void setMaxTimeout(long time) {
        maxTimeout = time;
    }


    public void create() {
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    linkStart();
                }
            });
        } else {
            linkStart();
        }
    }

    private void linkStart() {
        try {
            socket = new Socket(ip, port);
            isConnected = socket.isConnected();
            if (isConnected && !socket.isClosed()) {
                inputStream = socket.getInputStream();
                inputStreamReader = new InputStreamReader(inputStream);
                in = new BufferedReader(inputStreamReader);
                outputStream = socket.getOutputStream();
                printWriter = new PrintWriter(outputStream);
                callBack.onConnected();
                startListen();
            }
        } catch (IOException e) {
            linkShutdown();
            e.printStackTrace();
        }
    }

    /**
     * 关闭链接，注意当isAutoReconnect为Ture时，
     * 此方法关闭后会自动重连，需要调用ondestroy或先将自动重连关闭
     */
    private void linkShutdown() {
        try {
            if (socket != null) {
                isConnected = false;
                if (!socket.isClosed()) {
                    if (!socket.isInputShutdown()) {
                        socket.shutdownInput();
                    }
                    if (!socket.isOutputShutdown()) {
                        socket.shutdownOutput();
                    }
                    if (in != null) {
                        in.close();
                        in = null;
                    }
                    if (inputStreamReader != null) {
                        inputStreamReader.close();
                        inputStreamReader = null;
                    }
                    if (printWriter != null) {
                        printWriter.close();
                        printWriter = null;
                    }
                    if (outputStream != null) {
                        outputStream.close();
                        outputStream = null;
                    }
                    socket.close();
                }
                socket = null;
                callBack.onDisconnected();
            }
        } catch (IOException io) {
            callBack.onError(io.getMessage());
        } finally {
            if (isAutoReconnect && !isConnected) {
                try {
                    Thread.sleep(reConnTime * 1000);
                    callBack.onReconnected();
                    create();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * keepalive 为true时自动发送心跳包，
     * 发送内容为defaultMsg，通过setDefaultMsg设置，默认为1
     */
    private void sendHeartMsg() {
        printWriter.println(defaultMsg);
        printWriter.flush();
        if (!waitResponce) {
            waitResponce = true;
            lastTime = System.currentTimeMillis();
        }
    }

    /**
     * 在子线程发送消息，发送成功回调onsend
     * @param msg
     */
    public void sendMsg(final String msg) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                printWriter.println(msg);
                printWriter.flush();
                callBack.onSend();
                if (!waitResponce) {
                    waitResponce = true;
                    lastTime = System.currentTimeMillis();
                }

            }
        });
    }

    /**
     * 开始监听线程，并将接收到的数据转到主线程并回调OnRecived
     */
    private void startListen() {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                int rclen;
                while (isConnected) {
                    try {
                        Thread.sleep(5000);
                        if (waitResponce) {
                            if ((System.currentTimeMillis() - lastTime) > maxTimeout) {
                                isConnected = false;
                            }
                            if (isAutoReconnect)
                            {
                                linkShutdown();
                                callBack.onReconnected();
                                create();
                                continue;
                            }
                        }
                        if (keepAlive) {
                            sendHeartMsg();
                        }
                        rclen = inputStream.read(buffer);
                        if (rclen > 0) {
                            waitResponce=false;
                            final String rcMsg = new String(buffer, 0, rclen, charsetName);
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (callBack.type == String.class || callBack.type == Integer.class || callBack.type == Double.class || callBack.type == Float.class) {
                                        callBack.onReceived((T) rcMsg);
                                    } else {
                                        callBack.onReceived((T) JSON.parseObject(rcMsg,callBack.type));
                                    }
                                }
                            });
                        }
                    } catch (IOException io) {
                        callBack.onError(io.getMessage());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    /**
     * 不再使用时务必调用onDestroy方法释放
     */
    public void onDestory() {
        isAutoReconnect =false;
        linkShutdown();
        if (callBack != null) {
            callBack = null;
        }
    }


}
